﻿using System;
using System.Collections.Generic;
using System.Linq;
using HQPad.DAL;
using HQPad.Models;

namespace HQPad.Services
{
    public interface IGuildService
    {
        IEnumerable<Guild> GetGuilds(int ruleSetId);
        IEnumerable<Guild> GetGuilds(int ruleSetId, string characterClass);
        Guild GetGuild(int guildId);
        Guild GetGuild(int ruleSetId, string guildSlug);
        IEnumerable<Guild> GetGuilds(int ruleSetId, string[] guildSlugs);
        IEnumerable<Guild> GetGuildsWithInvocations(int ruleSetId);
        string CreateGuildSlug(string guildName);
        Guild AddGuild(int ruleSetId, string name, string slug, string primaryClass, string description);
        IEnumerable<Guild> GetAllowedGuilds(int ruleSetId, string primarySlug);
        IEnumerable<Guild> GetAllowedGuilds(int guildId);
    }

    public class GuildService : IGuildService
    {
        private HQContext context = null;

        public GuildService(IUnitOfWork context)
        {
            this.context = (HQContext)context;
        }

        #region AddGuild
        /// <summary>
        /// Add a new guild record.
        /// </summary>
        /// <param name="ruleSetId"></param>
        /// <param name="name"></param>
        /// <param name="slug"></param>
        /// <param name="primaryClass"></param>
        /// <param name="description"></param>
        /// <returns></returns>
        public Guild AddGuild(int ruleSetId, string name, string slug, string primaryClass, string description)
        {
            if (primaryClass != "Warrior" && primaryClass != "Mage" && primaryClass != "Acolyte" && primaryClass != "Scout")
                throw new ApplicationException(string.Format("Invalid class name for guild primary class {0}", primaryClass));

            Guild guild = new Guild()
            {
                Description = description,
                Name = name,
                PrimaryClass = primaryClass,
                RuleSetID = ruleSetId,
                Slug = slug
            };

            context.Guilds.Add(guild);

            return guild;
        }
        #endregion


        #region GetGuilds
        /// <summary>Get all guilds in a rule set.</summary>
        /// <param name="ruleSetId">The rule set id.</param>
        /// <returns></returns>
        public IEnumerable<Guild> GetGuilds(int ruleSetId)
        {
            return context.Guilds
                .Where(g => g.RuleSetID == ruleSetId);
        }

        /// <summary>
        /// Gett guilds by primary class.
        /// </summary>
        /// <param name="ruleSetId">The rule set id.</param>
        /// <param name="characterClass">The string class name.</param>
        /// <returns></returns>
        public IEnumerable<Guild> GetGuilds(int ruleSetId, string characterClass)
        {
            return context.Guilds
                .Where(g => g.RuleSetID == ruleSetId && g.PrimaryClass == characterClass);
        }

        /// <summary>
        /// Get guilds whose slug is contained in a list.
        /// </summary>
        /// <param name="ruleSetId">A rule set id.</param>
        /// <param name="guildSlugs">A string array of guild slugs that we want to return.</param>
        /// <returns>A list of guilds.</returns>
        public IEnumerable<Guild> GetGuilds(int ruleSetId, string[] guildSlugs)
        {
            return context.Guilds
                .Where(g => g.RuleSetID == ruleSetId && guildSlugs.Contains(g.Slug));
        }

        #endregion

        #region GetGuild
        /// <summary>Get a guild by it's unique id.</summary>
        /// <param name="guildId">A guild id.</param>
        /// <returns>The guild object found or null.</returns>
        public Guild GetGuild(int guildId)
        {
            return this.context.Guilds.Find(guildId);
        }

        /// <summary>
        /// Get a guild from a rule set by unique slug.
        /// </summary>
        /// <param name="ruleSetId">The id of the rule set.</param>
        /// <param name="guildSlug">The unique guild slug.</param>
        /// <returns>The guild found or null.</returns>
        public Guild GetGuild(int ruleSetId, string guildSlug)
        {
            return (from g in this.context.Guilds
                    where g.RuleSetID == ruleSetId && g.Slug == guildSlug
                    select g)
                    .FirstOrDefault();
        }
        #endregion

        #region GetGuildsWithInvocations
        /// <summary>Get a list of guilds that have at least one invocation assigned to them.</summary>
        /// <param name="ruleSetId">A rule set id.</param>
        /// <returns>A list of guilds or null.</returns>
        public IEnumerable<Guild> GetGuildsWithInvocations(int ruleSetId)
        {
             return
                (from i in context.Invocations
                from g in i.Guilds
                select g).Distinct();
        }
        #endregion

        #region CreateGuildSlug
        /// <summary>Create a guild slug from a guild name.</summary>
        /// <param name="guildName">The name of the guild</param>
        /// <returns>The standard format guild slug.</returns>
        public string CreateGuildSlug(string guildName)
        {
            return guildName
                .Replace("_", "")
                .Replace("-", "")
                .Replace("&", "")
                .Replace("+", "")
                .Replace(",", "")
                .Replace(".", "")
                .Replace(" ", "-")
                .Replace("--", "-")
                .Replace("--", "-")
                .ToLower();
        }
        #endregion

        #region GetAllowedGuilds
        /// <summary>
        /// Get allowed sub guilds for a guild.
        /// </summary>
        /// <param name="ruleSetId">The rule set id.</param>
        /// <param name="primarySlug">The guild url slug.</param>
        /// <returns>All allowed guilds.</returns>
        public IEnumerable<Guild> GetAllowedGuilds(int ruleSetId, string primarySlug)
        {
            return (from g in context.Guilds
                    from a in g.AllowedGuilds
                    where g.RuleSetID == ruleSetId && g.Slug == primarySlug
                    select a); 
        }

        /// <summary>
        /// Get allowed sub guilds for a guild.
        /// </summary>
        /// <param name="ruleSetId">The rule set id.</param>
        /// <param name="primarySlug">The guild url slug.</param>
        /// <returns>All allowed guilds.</returns>
        public IEnumerable<Guild> GetAllowedGuilds(int guildId)
        {
            return (from g in context.Guilds
                     from a in g.AllowedGuilds
                     where g.GuildID == guildId
                     select a);
        }        
        #endregion
    }
}